package com.icehand.utils.okhttp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.icehand.utils.constants.CodeType;
import com.icehand.utils.constants.HttpRequestMethodType;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import okhttp3.*;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.icehand.utils.constants.HttpRequestMethodType.POST;


/**
*  okhttp工具类
 * Created by icehand on 2016/4/17.
 */
public class OkHttpUtils {
	private final static Logger log = LoggerFactory.getLogger(OkHttpUtils.class);

	private final static String DEFAULT_CHARSET = CodeType.UTF8;
	private final static String DEFAULT_METHOD = HttpRequestMethodType.GET;
	private final static MediaType DEFAULT_MEDIA_TYPE = MediaType.parse("application/json,utf-8");
	private final static boolean DEFAULT_LOG = false;

	private final static OkHttpClient client = new OkHttpClient.Builder()
			.connectionPool(new ConnectionPool(20, 5, TimeUnit.MINUTES))
			.readTimeout(20, TimeUnit.SECONDS)
			.connectTimeout(20, TimeUnit.SECONDS).build();

	/**
	 * GET请求
	 * @param url
	 * URL地址
	 * @return String
	 */
	public static String get(String url){
		return execute(OkHttp.builder().url(url).build());
	}

	/**
	 * GET请求
	 * @param url
	 * URL地址
	 * @return String
	 */
	public static String get(String url, String charset){
		return execute(OkHttp.builder().url(url).responseCharset(charset).build());
	}

	/**
	 * 带查询参数的GET查询
	 * @param url
	 * URL地址
	 * @param queryMap
	 * 查询参数
	 * @return String
	 */
	public static String get(String url,  Map<String, String> queryMap){
		return execute(OkHttp.builder().url(url).queryMap(queryMap).build());
	}

	/**
	 * 带查询参数的GET查询
	 * @param url
	 * URL地址
	 * @param queryMap
	 * 查询参数
	 * @return String
	 */
	public static String get(String url,  Map<String, String> queryMap, String charset){
		return execute(OkHttp.builder().url(url).queryMap(queryMap).responseCharset(charset).build());
	}

	/**
	 * POST
	 * application/json
	 * @param url 地址
	 * @param obj JSON对象
	 * @return String
	 */
	public static String postJson(String url, Object obj){
		return execute(OkHttp.builder().url(url).method(POST).data(JSON.toJSONString(obj)).mediaType(DEFAULT_MEDIA_TYPE).build());
	}

	public static String postJson(String url, Object obj,Map<String,String> header){
		return execute(OkHttp.builder().url(url).method(POST).data(JSON.toJSONString(obj)).headerMap(header).mediaType(DEFAULT_MEDIA_TYPE).build());
	}

	/**
	 * 通用执行方法
	 */
	private static String execute(OkHttp okHttp){
		if(StringUtils.isBlank(okHttp.requestCharset)){
			okHttp.requestCharset = DEFAULT_CHARSET;
		}
		if(StringUtils.isBlank(okHttp.responseCharset)){
			okHttp.responseCharset = DEFAULT_CHARSET;
		}
		if(StringUtils.isBlank(okHttp.method)){
			okHttp.method = DEFAULT_METHOD;
		}
		if(null == okHttp.mediaType){
			okHttp.mediaType = DEFAULT_MEDIA_TYPE;
		}
		if(okHttp.requestLog){//记录请求日志
			log.info(okHttp.toString());
		}

		String url =okHttp.url;

		Request.Builder builder = new Request.Builder();

		if(MapUtils.isNotEmpty(okHttp.queryMap)){
			String queryParams = okHttp.queryMap.entrySet().stream()
					.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
					.collect(Collectors.joining("&"));
			url = String.format("%s%s%s", url, url.contains("?")?"&":"?", queryParams);
		}
		builder.url(url);

		if(MapUtils.isNotEmpty(okHttp.headerMap)){
			okHttp.headerMap.forEach(builder::addHeader);
		}

		String method = okHttp.method.toUpperCase();
		String mediaType = String.format("%s;charset=%s", okHttp.mediaType, okHttp.requestCharset);

		if(StringUtils.equals(method, HttpRequestMethodType.GET)){
			builder.get();
		}else if(ArrayUtils.contains(new String[]{POST, HttpRequestMethodType.PUT, HttpRequestMethodType.DELETE, HttpRequestMethodType.PATCH}, method)){
			RequestBody requestBody = RequestBody.create(MediaType.parse(mediaType), okHttp.data);
			builder.method(method, requestBody);
		}else{
			log.error(String.format("http method:%s not support!", method));
		}

		String result = "";
		try {
			Response response = client.newCall(builder.build()).execute();
			byte[] bytes = response.body().bytes();
			result = new String(bytes, okHttp.responseCharset);
			if (okHttp.responseLog){//记录返回日志
				log.info(String.format("Got response->%s",result));
			}
		}catch (Exception e){
			log.error(okHttp.toString(), e);
		}
		return result;
	}

	@Data
	@Builder
	@ToString(exclude = {"requestCharset", "responseCharset", "requestLog", "responseLog" })
	private static class OkHttp{
		private String url;
		private String method = DEFAULT_METHOD;
		private String data;
		private MediaType mediaType = DEFAULT_MEDIA_TYPE;
		private Map<String, String> queryMap;
		private Map<String, String> headerMap;
		private String requestCharset = DEFAULT_CHARSET;
		private boolean requestLog = DEFAULT_LOG;

		private String responseCharset = DEFAULT_CHARSET;
		private boolean responseLog = DEFAULT_LOG;
	}
}